home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / awksrc.zip / NODE.C < prev    next >
C/C++ Source or Header  |  1993-09-28  |  9KB  |  434 lines

  1. /*
  2.  * node.c -- routines for node management
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27. extern double strtod( const char *nptr, char **endptr );
  28. extern char *getenv( const char *varname );
  29.  
  30.  
  31. AWKNUM
  32. r_force_number(n)
  33. register NODE *n;
  34. {
  35.     register char *cp;
  36.     register char *cpend;
  37.     char save;
  38.     char *ptr;
  39.     unsigned int newflags = 0;
  40.  
  41. #ifdef DEBUG
  42.     if (n == NULL)
  43.         cant_happen();
  44.     if (n->type != Node_val)
  45.         cant_happen();
  46.     if(n->flags == 0)
  47.         cant_happen();
  48.     if (n->flags & NUM)
  49.         return n->numbr;
  50. #endif
  51.  
  52.     /* all the conditionals are an attempt to avoid the expensive strtod */
  53.  
  54.     n->numbr = 0.0;
  55.     n->flags |= NUM;
  56.  
  57.     if (n->stlen == 0)
  58.         return 0.0;
  59.  
  60.     cp = n->stptr;
  61.     if (isalpha(*cp))
  62.         return 0.0;
  63.  
  64.     cpend = cp + n->stlen;
  65.     while (cp < cpend && isspace(*cp))
  66.         cp++;
  67.     if (cp == cpend || isalpha(*cp))
  68.         return 0.0;
  69.  
  70.     if (n->flags & MAYBE_NUM) {
  71.         newflags = NUMBER;
  72.         n->flags &= ~MAYBE_NUM;
  73.     }
  74.     if (cpend - cp == 1) {
  75.         if (isdigit(*cp)) {
  76.             n->numbr = (AWKNUM)(*cp - '0');
  77.             n->flags |= newflags;
  78.         }
  79.         return n->numbr;
  80.     }
  81.  
  82.     errno = 0;
  83.     save = *cpend;
  84.     *cpend = '\0';
  85.     n->numbr = (AWKNUM) strtod((const char *)cp, &ptr);
  86.  
  87.     /* POSIX says trailing space is OK for NUMBER */
  88.     while (isspace(*ptr))
  89.         ptr++;
  90.     *cpend = save;
  91.     /* the >= should be ==, but for SunOS 3.5 strtod() */
  92.     if (errno == 0 && ptr >= cpend)
  93.         n->flags |= newflags;
  94.     else
  95.         errno = 0;
  96.  
  97.     return n->numbr;
  98. }
  99.  
  100. /*
  101.  * the following lookup table is used as an optimization in force_string
  102.  * (more complicated) variations on this theme didn't seem to pay off, but 
  103.  * systematic testing might be in order at some point
  104.  */
  105. static char *values[] = {
  106.     "0",
  107.     "1",
  108.     "2",
  109.     "3",
  110.     "4",
  111.     "5",
  112.     "6",
  113.     "7",
  114.     "8",
  115.     "9",
  116. };
  117. #define    NVAL    (sizeof(values)/sizeof(values[0]))
  118.  
  119. NODE *
  120. r_force_string(s)
  121. register NODE *s;
  122. {
  123.     char buf[128];
  124.     register char *sp = buf;
  125.     register long num = 0;
  126.  
  127. #ifdef DEBUG
  128.     if (s == NULL) cant_happen();
  129.     if (s->type != Node_val) cant_happen();
  130.     if (s->flags & STR) return s;
  131.     if (!(s->flags & NUM)) cant_happen();
  132.     if (s->stref != 0) ; /*cant_happen();*/
  133. #endif
  134.  
  135.         /* avoids floating point exception in DOS*/
  136.         if ( s->numbr <= LONG_MAX && s->numbr >= -LONG_MAX)
  137.         num = (long)s->numbr;
  138.     if ((AWKNUM) num == s->numbr) {    /* integral value */
  139.         if (num < NVAL && num >= 0) {
  140.             sp = values[num];
  141.             s->stlen = 1;
  142.         } else {
  143.             (void) sprintf(sp, "%ld", num);
  144.             s->stlen = strlen(sp);
  145.         }
  146.         s->stfmt = -1;
  147.     } else {
  148.         (void) sprintf(sp, CONVFMT, s->numbr);
  149.         s->stlen = strlen(sp);
  150.         s->stfmt = (char)CONVFMTidx;
  151.     }
  152.     s->stref = 1;
  153.     emalloc(s->stptr, char *, s->stlen + 2, "force_string");
  154.     memcpy(s->stptr, sp, s->stlen+1);
  155.     s->flags |= STR;
  156.     return s;
  157. }
  158.  
  159. /*
  160.  * Duplicate a node.  (For strings, "duplicate" means crank up the
  161.  * reference count.)
  162.  */
  163. NODE *
  164. dupnode(n)
  165. NODE *n;
  166. {
  167.     register NODE *r;
  168.  
  169.     if (n->flags & TEMP) {
  170.         n->flags &= ~TEMP;
  171.         n->flags |= MALLOC;
  172.         return n;
  173.     }
  174.     if ((n->flags & (MALLOC|STR)) == (MALLOC|STR)) {
  175.         if (n->stref < 255)
  176.             n->stref++;
  177.         return n;
  178.     }
  179.     getnode(r);
  180.     *r = *n;
  181.     r->flags &= ~(PERM|TEMP);
  182.     r->flags |= MALLOC;
  183.     if (n->type == Node_val && (n->flags & STR)) {
  184.         r->stref = 1;
  185.         emalloc(r->stptr, char *, r->stlen + 2, "dupnode");
  186.         memcpy(r->stptr, n->stptr, r->stlen+1);
  187.     }
  188.     return r;
  189. }
  190.  
  191. /* this allocates a node with defined numbr */
  192. NODE *
  193. mk_number(x, flags)
  194. AWKNUM x;
  195. unsigned int flags;
  196. {
  197.     register NODE *r;
  198.  
  199.     getnode(r);
  200.     r->type = Node_val;
  201.     r->numbr = x;
  202.     r->flags = flags;
  203. #ifdef DEBUG
  204.     r->stref = 1;
  205.     r->stptr = 0;
  206.     r->stlen = 0;
  207. #endif
  208.     return r;
  209. }
  210.  
  211. /*
  212.  * Make a string node.
  213.  */
  214. NODE *
  215. make_str_node(s, len, flags)
  216. char *s;
  217. size_t len;
  218. int flags;
  219. {
  220.     register NODE *r;
  221.  
  222.     getnode(r);
  223.     r->type = Node_val;
  224.     r->flags = (STRING|STR|MALLOC);
  225.     if (flags & ALREADY_MALLOCED)
  226.         r->stptr = s;
  227.     else {
  228.         emalloc(r->stptr, char *, len + 2, s);
  229.         memcpy(r->stptr, s, len);
  230.     }
  231.     r->stptr[len] = '\0';
  232.            
  233.     if (flags & SCAN) {    /* scan for escape sequences */
  234.         char *pf;
  235.         register char *ptm;
  236.         register int c;
  237.         register char *end;
  238.  
  239.         end = &(r->stptr[len]);
  240.         for (pf = ptm = r->stptr; pf < end;) {
  241.             c = *pf++;
  242.             if (c == '\\') {
  243.                 c = parse_escape(&pf);
  244.                 if (c < 0) {
  245.                     if (do_lint)
  246.                         warning("backslash at end of string");
  247.                     c = '\\';
  248.                 }
  249.                 *ptm++ = c;
  250.             } else
  251.                 *ptm++ = c;
  252.         }
  253.         len = ptm - r->stptr;
  254.         erealloc(r->stptr, char *, len + 1, "make_str_node");
  255.         r->stptr[len] = '\0';
  256.         r->flags |= PERM;
  257.     }
  258.     r->stlen = len;
  259.     r->stref = 1;
  260.     r->stfmt = -1;
  261.  
  262.     return r;
  263. }
  264.  
  265. NODE *
  266. tmp_string(s, len)
  267. char *s;
  268. size_t len;
  269. {
  270.     register NODE *r;
  271.  
  272.     r = make_string(s, len);
  273.     r->flags |= TEMP;
  274.     return r;
  275. }
  276.  
  277.  
  278. #define NODECHUNK    100
  279.  
  280. NODE *nextfree = NULL;
  281.  
  282. NODE *
  283. more_nodes()
  284. {
  285.     register NODE *np;
  286.  
  287.     /* get more nodes and initialize list */
  288.     emalloc(nextfree, NODE *, NODECHUNK * sizeof(NODE), "newnode");
  289.     for (np = nextfree; np < &nextfree[NODECHUNK - 1]; np++)
  290.         np->nextp = np + 1;
  291.     np->nextp = NULL;
  292.     np = nextfree;
  293.     nextfree = nextfree->nextp;
  294.     return np;
  295. }
  296.  
  297. #ifdef DEBUG
  298. void
  299. freenode(it)
  300. NODE *it;
  301. {
  302. #ifdef MPROF
  303.     it->stref = 0;
  304.     free((char *) it);
  305. #else
  306. #ifdef MALLOCDEBUG
  307.     memset(it, '\04', sizeof(*it));
  308. #endif
  309.     /* add it to head of freelist */
  310.     it->nextp = nextfree;
  311.     nextfree = it;
  312. #endif
  313. }
  314. #endif
  315.  
  316. void
  317. unref(tmp)
  318. register NODE *tmp;
  319. {
  320.     if (tmp == NULL)
  321.         return;
  322.     if (tmp->flags & PERM)
  323.         return;
  324.     if (tmp->flags & (MALLOC|TEMP)) {
  325.         tmp->flags &= ~TEMP;
  326.         if (tmp->flags & STR) {
  327.             if (tmp->stref > 1) {
  328.                 if (tmp->stref != 255)
  329.                     tmp->stref--;
  330.                 return;
  331.             }
  332.             free(tmp->stptr);
  333.         }
  334.         freenode(tmp);
  335.     }
  336. }
  337.  
  338. /*
  339.  * Parse a C escape sequence.  STRING_PTR points to a variable containing a
  340.  * pointer to the string to parse.  That pointer is updated past the
  341.  * characters we use.  The value of the escape sequence is returned. 
  342.  *
  343.  * A negative value means the sequence \ newline was seen, which is supposed to
  344.  * be equivalent to nothing at all. 
  345.  *
  346.  * If \ is followed by a null character, we return a negative value and leave
  347.  * the string pointer pointing at the null character. 
  348.  *
  349.  * If \ is followed by 000, we return 0 and leave the string pointer after the
  350.  * zeros.  A value of 0 does not mean end of string.  
  351.  *
  352.  * Posix doesn't allow \x.
  353.  */
  354.  
  355. int
  356. parse_escape(string_ptr)
  357. char **string_ptr;
  358. {
  359.     register int c = *(*string_ptr)++;
  360.     register int i;
  361.     register int count;
  362.  
  363.     switch (c) {
  364.     case 'a':
  365.         return BELL;
  366.     case 'b':
  367.         return '\b';
  368.     case 'f':
  369.         return '\f';
  370.     case 'n':
  371.         return '\n';
  372.     case 'r':
  373.         return '\r';
  374.     case 't':
  375.         return '\t';
  376.     case 'v':
  377.         return '\v';
  378.     case '\n':
  379.         return -2;
  380.     case 0:
  381.         (*string_ptr)--;
  382.         return -1;
  383.     case '0':
  384.     case '1':
  385.     case '2':
  386.     case '3':
  387.     case '4':
  388.     case '5':
  389.     case '6':
  390.     case '7':
  391.         i = c - '0';
  392.         count = 0;
  393.         while (++count < 3) {
  394.             if ((c = *(*string_ptr)++) >= '0' && c <= '7') {
  395.                 i *= 8;
  396.                 i += c - '0';
  397.             } else {
  398.                 (*string_ptr)--;
  399.                 break;
  400.             }
  401.         }
  402.         return i;
  403.     case 'x':
  404.         if (do_lint) {
  405.             static int didwarn;
  406.  
  407.             if (! didwarn) {
  408.                 didwarn = 1;
  409.                 warning("Posix does not allow \"\\x\" escapes");
  410.             }
  411.         }
  412.         if (do_posix)
  413.             return ('x');
  414.         i = 0;
  415.         while (1) {
  416.             if (isxdigit((c = *(*string_ptr)++))) {
  417.                 i *= 16;
  418.                 if (isdigit(c))
  419.                     i += c - '0';
  420.                 else if (isupper(c))
  421.                     i += c - 'A' + 10;
  422.                 else
  423.                     i += c - 'a' + 10;
  424.             } else {
  425.                 (*string_ptr)--;
  426.                 break;
  427.             }
  428.         }
  429.         return i;
  430.     default:
  431.         return c;
  432.     }
  433. }
  434.